﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.IO;
using System.Globalization;
using System.Text.RegularExpressions;

namespace TravianLib
{
    public class Player
    {
        private string _xmlFile;
        private int _playerID = 12345;
        private HTTPFetch _httpFetch;
  
        public dBreport ReportDB { get; private set; }       
        public List<VillageNew> Villages
        {
            get;
            private set;
        }

        public Player(string username, HTTPFetch httpfetch)
        {
            ReportDB = new dBreport();
            if (File.Exists(_playerID + "_reports.xml"))
            {
                ReportDB.ReadXml(_playerID + "_reports.xml");
            }
            Villages = new List<VillageNew>();
            _xmlFile = username + ".conf";            
            _httpFetch = httpfetch;
            _httpFetch.NewReport += new EventHandler(httpfetch_NewReport);
            getVillages();
        }
                
        private void httpfetch_NewReport(object sender, EventArgs e)
        {            
            ServiceReference1.Service1SoapClient world = new TravianLib.ServiceReference1.Service1SoapClient();
            string output = _httpFetch.createHTTPrequest("/berichte.php");
            MatchCollection IDs = new Regex("<a href=\"berichte.php.id=([0-9]+)").Matches(output);
            foreach (Match item in IDs)
            {
                int ID = int.Parse(item.Groups[1].Value);
                var q = (from c in ReportDB.report
                         where c.TravianReportID == ID
                         select c).SingleOrDefault();
                if (q == null)
                {
                    try
                    {
                        output = _httpFetch.createHTTPrequest("/berichte.php?id=" + ID);
                        q = this.ReportDB.report.NewreportRow();
                        q = parseReport(output);
                        q.TravianReportID = ID;       
                        ReportDB.report.AddreportRow(q);
                        ReportDB.report.AcceptChanges();
                        tweakSquadSize(world, ID);                        
                    }
                    catch (Exception ex) {
                        File.WriteAllText(ID + "_notParsed.php", ex.ToString() + "\n" + output);
                    }
                }
            }
        }
        private void tweakSquadSize(ServiceReference1.Service1SoapClient world, int ID)
        {
            var o = (from t1 in ReportDB.report
                     join t2 in ReportDB.participant
                       on t1.ID equals t2.ReportID
                     where t1.TravianReportID == ID && !t2.Role
                     //orderby t2.ID
                     orderby t1.Date descending
                     select new
                     {
                         Target = t2.TargetVillageC,
                         Eff = (double)(t1.Wood + t1.Clay + t1.Iron + t1.Crop) * 100 /
                         (from r2 in ReportDB.participant
                          join r3 in ReportDB.unit
                              on r2.ID equals r3.ParticipantID
                          where r2.ReportID == t1.ID && r2.Role
                          group r3 by r3.UnitType into g
                          select new
                          {
                              Capacity = (from u in TravianLib.Utils.TravianData.troops
                                          where u.ID == g.Key
                                          select u.Capacity).SingleOrDefault(),
                              Amount = g.Sum(j => j.Amount)
                          }).Sum(h => h.Capacity * h.Amount)
                     }).Where(b => !double.IsInfinity(b.Eff)).SingleOrDefault();
            if (o != null)
            {
                ServiceReference1.Village vil = world.getVillageByID(o.Target);
                System.Data.DataRow point = (from p in Villages[0].Barracks.Targets.Rows.Cast<System.Data.DataRow>()
                                             where int.Parse(p["x"].ToString()) == vil.X && int.Parse(p["y"].ToString()) == vil.Y
                                             select p).SingleOrDefault();
                double ef = o.Eff;
                if (point != null)
                {
                    int squadSize;
                    if (!int.TryParse(point["Squad Size"].ToString(), out squadSize))
                    {
                        squadSize = 4;
                    }
                    if (ef == 100)
                    {
                        point["Squad Size"] = squadSize + 2;
                    }
                    else if (ef > 85)
                    {
                        point["Squad Size"] = squadSize + 1;
                    }
                    else if (ef > 65)
                    {
                        point["Squad Size"] = squadSize;
                    }
                    else if (ef > 45)
                    {
                        point["Squad Size"] = squadSize - 1;
                    }
                    else if (ef == 0)
                    {
                        point["Squad Size"] = 2;
                    }
                    else
                    {
                        point["Squad Size"] = squadSize - 2;
                    }

                    if (int.Parse(point["Squad Size"].ToString()) < 2)
                    {
                        squadSize = 2;
                        point["Squad Size"] = squadSize;
                    }
                }
            }
        }
        private dBreport.reportRow parseReport(string input)
        {
            int i = 0;
            Regex participantRolesRgx = new Regex("cellspacing=\"1\" (class|id)=\"(attacker|defender)\"");
            Regex resourcesRgx = new Regex("(Puu|Rauta|Savi|Vilja).*?([0-9]+)");
            Regex villagesRgx = new Regex("karte.php.d=([0-9]+).*?c=([a-f0-9]+)");
            Regex unitTypeRgx = new Regex("u([0-9]+)");
            Regex unitAmountRgx = new Regex("<td( class=\"none\")*>([0-9]+)</td>");

            MatchCollection resourcesCol = resourcesRgx.Matches(input);
            MatchCollection villagesCol = villagesRgx.Matches(input);
            MatchCollection unitTypeCol = unitTypeRgx.Matches(input);
            MatchCollection unitAmountCol = unitAmountRgx.Matches(input);

            dBreport.reportRow q = this.ReportDB.report.NewreportRow();

            q.Wood = int.Parse(resourcesRgx.Matches(input)[0].Groups[2].Value);
            q.Clay = int.Parse(resourcesRgx.Matches(input)[1].Groups[2].Value);
            q.Iron = int.Parse(resourcesRgx.Matches(input)[2].Groups[2].Value);
            q.Crop = int.Parse(resourcesRgx.Matches(input)[3].Groups[2].Value);
            q.Date = DateTime.Now;

            foreach (Match participantRole in participantRolesRgx.Matches(input))
            {
                dBreport.participantRow p = this.ReportDB.participant.NewparticipantRow();
                p.Role = participantRole.Groups[2].Value == "attacker" ? true : false;
                p.TargetVillageC = int.Parse(villagesCol[i].Groups[1].Value);
                p.TargetVillageD = int.Parse(villagesCol[i].Groups[2].Value, System.Globalization.NumberStyles.HexNumber);
                int o = i;
                for (o = i * 20; o < 10; o++)
                {
                    if (int.Parse(unitAmountCol[o].Groups[2].Value) != 0)
                    {
                        dBreport.unitRow u = this.ReportDB.unit.NewunitRow();
                        u.Amount = int.Parse(unitAmountCol[o].Groups[2].Value);
                        u.Loss = int.Parse(unitAmountCol[10 + o].Groups[2].Value);
                        u.UnitType = int.Parse(unitTypeCol[o].Groups[1].Value);
                        u.participantRow = p;
                        this.ReportDB.unit.AddunitRow(u);
                    }
                }
                p.reportRow = q;
                this.ReportDB.participant.AddparticipantRow(p);
                i++;
            }
            return q;
        }
        private void getVillages() {
            
            System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex("dorf1.php.newdid=([0-9]+)");
            foreach (System.Text.RegularExpressions.Match match in rgx.Matches(_httpFetch.createHTTPrequest("/dorf3.php")))
            {
                VillageNew vil = new VillageNew(_httpFetch, int.Parse(match.Groups[1].Value));
                Villages.Add(vil);
            }
        }

        ~Player()
        {
            _httpFetch.WriteXml();
            ReportDB.WriteXml(_playerID + "_reports.xml");
        }
    }
}
